#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "TDA_lexico.h"


void token_reset(Token* token){ /* Resetea token. Si token no esta inicializado, lo inicializa. */
    token->tipo=TOKEN_VACIO;
    token->dato[0]='\0';
    return;
}

int char_valido(char c){   			/* Comprueba que el caracter c este dentro de los caracteres permitidos. */
    if(isalnum(c)||(c==' ')||(c==':')||(c==',')||(c=='"')||(c=='[')||(c==']')||(c=='{')||(c=='}')||(c=='\n')||(c=='\r')||(c=='\t'))
        return 1; /*Caracter valido*/
    return 0; /*Caracter invalido*/
}

int TLexico_Crear(TLexico* al){
    token_reset(&al->token);
    al->el=ERROR_NULL_L;
    al->es=0;
    return 0;
}

int TLexico_setAnalizadorSintactico(TLexico* al, TSintactico* as){
    al->as=as;
    return 0;
}

int TLexico_getUltimoError(TLexico* al, int* codigo, char* mensaje){
    if(al->es){
        TSintactico_getUltimoError(al->as,codigo,mensaje);
        return 0;
    }
    *codigo=al->el;
    switch(al->el){
        case ERROR_CHAR_NO_PERMITIDO: strcpy(mensaje,"Caracter incompatible con JSON");
                                      break;
        case ERROR_AUSENCIA_COMILLAS: strcpy(mensaje,"Las cadenas de caracteres deben estar encerradas por comillas");
                                      break;
        case ERROR_DENTRO_CADENA: strcpy(mensaje,"Caracter no permitido dentro de una cadena");
                                  break;
        case ERROR_NULL_L: strcpy(mensaje,"No se produjo ningun error");
                           break;
    }
    return 0;
}

int TLexico_terminarFlujo(TLexico* al){
    int ce; /*Codigo Error*/
    int long_cad;
    switch(al->token.tipo){
        case TOKEN_VACIO:  ce=TSintactico_terminarFlujo(al->as);
                           if(ce){
                              al->es=1;   /*Error sintactico verdadero*/
                              return ce;
                           }
                           TLexico_Crear(al);
                           return 0;
        case TOKEN_STRING: printf("ERROR LEXICO\n\n");
                           al->el=ERROR_AUSENCIA_COMILLAS;
                           return ERROR_AUSENCIA_COMILLAS;
        case TOKEN_NUMERO: ce=TSintactico_PushToken(al->as,&al->token);
                           if(ce){
                              al->es=1;   /*Error sintactico verdadero*/
                              return ce;
                           }
                           ce=TSintactico_terminarFlujo(al->as);
                           if(ce){
                              al->es=1;   /*Error sintactico verdadero*/
                              return ce;
                           }
                           TLexico_Crear(al);
                           return 0;
        case TOKEN_FALSE: long_cad=strlen(al->token.dato);
                          if(long_cad==5){
                             int i;
                             for(i=0;i<=4;i++)
                                al->token.dato[i]='\0';
                             ce=TSintactico_PushToken(al->as,&al->token);
                             if(ce){
                                al->es=1;   /*Error sintactico verdadero*/
                                return ce;
                             }
                             else{
                                ce=TSintactico_terminarFlujo(al->as);
                                if(ce){
                                   al->es=1;   /*Error sintactico verdadero*/
                                   return ce;
                                }
                                TLexico_Crear(al);
                                return 0;
                             }
                          }
                          else{
                             printf("ERROR LEXICO\n\n");
                             al->el=ERROR_AUSENCIA_COMILLAS;
                             return ERROR_AUSENCIA_COMILLAS;
                          }
                          /*case TOKEN_TRUE o TOKEN_NULL*/
        default: long_cad=strlen(al->token.dato);
                 if(long_cad==4){
                    int i;
                    for(i=0;i<=3;i++)
                       al->token.dato[i]='\0';
                    ce=TSintactico_PushToken(al->as,&al->token);
                    if(ce){
                       al->es=1;   /*Error sintactico verdadero*/
                       return ce;
                    }
                    else{
                       ce=TSintactico_terminarFlujo(al->as);
                       if(ce){
                          al->es=1;   /*Error sintactico verdadero*/
                          return ce;
                       }
                       TLexico_Crear(al);
                       return 0;
                    }
                 }
                 else{
                    printf("ERROR LEXICO\n\n");
                    al->el=ERROR_AUSENCIA_COMILLAS;
                    return ERROR_AUSENCIA_COMILLAS;
                 }
    }
}

int case_token_vacio(TLexico* al, char c){
    int ce; /*Codigo Error*/
    if(char_valido(c)){
        if(isdigit(c)){
            al->token.tipo=TOKEN_NUMERO;
            al->token.dato[0]=c;
            al->token.dato[1]='\0';
            return 0;
        }
        switch(c){
            case '\t': return 0;
            case '\n': return 0;
            case '\r' :return 0;
            case ' ':return 0;
            case '{':al->token.tipo=TOKEN_OBJETO_EMPIEZA;
                     ce=TSintactico_PushToken(al->as,&al->token);
                     if(ce){
                        al->es=1;   /*Error sintactico verdadero*/
                        return ce;
                     }
                     token_reset(&al->token);
                     return 0;
            case '}':al->token.tipo=TOKEN_OBJETO_TERMINA;
                     ce=TSintactico_PushToken(al->as,&al->token);
                     if(ce){
                        al->es=1;   /*Error sintactico verdadero*/
                        return ce;
                     }
                     token_reset(&al->token);
                     return 0;
            case '[':al->token.tipo=TOKEN_ARRAY_EMPIEZA;
                     ce=TSintactico_PushToken(al->as,&al->token);
                     if(ce){
                        al->es=1;   /*Error sintactico verdadero*/
                        return ce;
                     }
                     token_reset(&al->token);
                     return 0;
            case ']':al->token.tipo=TOKEN_ARRAY_TERMINA;
                     ce=TSintactico_PushToken(al->as,&al->token);
                     if(ce){
                        al->es=1;   /*Error sintactico verdadero*/
                        return ce;
                     }
                     token_reset(&al->token);
                     return 0;
            case '"':al->token.tipo=TOKEN_STRING;
                     return 0;
            case ':':al->token.tipo=TOKEN_DOSPUNTOS;
                     ce=TSintactico_PushToken(al->as,&al->token);
                     if(ce){
                        al->es=1;   /*Error sintactico verdadero*/
                        return ce;
                     }
                     token_reset(&al->token);
                     return 0;
            case ',':al->token.tipo=TOKEN_COMA;
                     ce=TSintactico_PushToken(al->as,&al->token);
                     if(ce){
                        al->es=1;   /*Error sintactico verdadero*/
                        return ce;
                     }
                     token_reset(&al->token);
                     return 0;
            case 't':al->token.tipo=TOKEN_TRUE;
                     al->token.dato[0]=c;
                     al->token.dato[1]='\0';
                     return 0;
            case 'f':al->token.tipo=TOKEN_FALSE;
                     al->token.dato[0]=c;
                     al->token.dato[1]='\0';
                     return 0;
            case 'n':al->token.tipo=TOKEN_NULL;
                     al->token.dato[0]=c;
                     al->token.dato[1]='\0';
                     return 0;
            default:printf("ERROR LEXICO\n\n");
                    al->el=ERROR_AUSENCIA_COMILLAS;
                    return ERROR_AUSENCIA_COMILLAS;
        }
    }
    else{
        al->el=ERROR_CHAR_NO_PERMITIDO;
        return ERROR_CHAR_NO_PERMITIDO;
    }
}


int case_token_string(TLexico* al, char c){
    int ce; /*Codigo Error*/
    if(char_valido(c)){
        if(isalnum(c)||c==' '){
            int long_cad=strlen(al->token.dato);
            al->token.dato[long_cad]=c;
            al->token.dato[long_cad+1]='\0';
            return 0;
        }
        else{
            if(c=='"'){
                ce=TSintactico_PushToken(al->as,&al->token);
                if(ce){
                    al->es=1;   /*Error sintactico verdadero*/
                    return ce;
                }
                token_reset(&al->token);
                return 0;
            }
            else{
                printf("ERROR LEXICO\n\n");
                al->el=ERROR_DENTRO_CADENA;
                return ERROR_DENTRO_CADENA;
            }
        }
    }
    else{
        printf("ERROR LEXICO\n\n");
        al->el=ERROR_CHAR_NO_PERMITIDO;
        return ERROR_CHAR_NO_PERMITIDO;
    }
}

int case_token_numero(TLexico* al, char c){
    int ce; /*Codigo Error*/
    if(char_valido(c)){
        if(isdigit(c)){
            int long_cad=strlen(al->token.dato);
            al->token.dato[long_cad]=c;
            al->token.dato[long_cad+1]='\0';
            return 0;
        }
        else{
            ce=TSintactico_PushToken(al->as,&al->token);
            if(ce){
                al->es=1;   /*Error sintactico verdadero*/
                return ce;
            }
            token_reset(&al->token);
            switch(c){
                case '\t': return 0;
                case '\n': return 0;
                case '\r' :return 0;
                case ' ':return 0;
                case '{':al->token.tipo=TOKEN_OBJETO_EMPIEZA;
                         ce=TSintactico_PushToken(al->as,&al->token);
                         if(ce){
                            al->es=1;   /*Error sintactico verdadero*/
                            return ce;
                         }
                         token_reset(&al->token);
                         return 0;
                case '}':al->token.tipo=TOKEN_OBJETO_TERMINA;
                         ce=TSintactico_PushToken(al->as,&al->token);
                         if(ce){
                            al->es=1;   /*Error sintactico verdadero*/
                            return ce;
                         }
                         token_reset(&al->token);
                         return 0;
                case '[':al->token.tipo=TOKEN_ARRAY_EMPIEZA;
                         ce=TSintactico_PushToken(al->as,&al->token);
                         if(ce){
                            al->es=1;   /*Error sintactico verdadero*/
                            return ce;
                         }
                         token_reset(&al->token);
                         return 0;
                case ']':al->token.tipo=TOKEN_ARRAY_TERMINA;
                         ce=TSintactico_PushToken(al->as,&al->token);
                         if(ce){
                            al->es=1;   /*Error sintactico verdadero*/
                            return ce;
                         }
                         token_reset(&al->token);
                         return 0;
                case '"':al->token.tipo=TOKEN_STRING;
                         return 0;
                case ':':al->token.tipo=TOKEN_DOSPUNTOS;
                         ce=TSintactico_PushToken(al->as,&al->token);
                         if(ce){
                            al->es=1;   /*Error sintactico verdadero*/
                            return ce;
                         }
                         token_reset(&al->token);
                         return 0;
                case ',':al->token.tipo=TOKEN_COMA;
                         ce=TSintactico_PushToken(al->as,&al->token);
                         if(ce){
                            al->es=1;   /*Error sintactico verdadero*/
                            return ce;
                         }
                         token_reset(&al->token);
                         return 0;
                case 't':al->token.tipo=TOKEN_TRUE;
                         al->token.dato[0]=c;
                         al->token.dato[1]='\0';
                         return 0;
                case 'f':al->token.tipo=TOKEN_FALSE;
                         al->token.dato[0]=c;
                         al->token.dato[1]='\0';
                         return 0;
                case 'n':al->token.tipo=TOKEN_NULL;
                         al->token.dato[0]=c;
                         al->token.dato[1]='\0';
                         return 0;
                default: printf("ERROR LEXICO\n\n");
                         al->el=ERROR_AUSENCIA_COMILLAS;
                         return ERROR_AUSENCIA_COMILLAS;
            }
        }
    }
    else{
        printf("ERROR LEXICO\n\n");
        al->el=ERROR_CHAR_NO_PERMITIDO;
        return ERROR_CHAR_NO_PERMITIDO;
    }
}

int case_token_true(TLexico* al, char c){
    int ce; /*Codigo Error*/
    if(char_valido(c)){
        int long_cad=strlen(al->token.dato);
        switch (long_cad){
            case 1: if(c=='r'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 2: if(c=='u'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 3: if(c=='e'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
                    case 4: if(isalnum(c)){
                                printf("ERROR LEXICO\n\n");
                                al->el=ERROR_AUSENCIA_COMILLAS;
                                return ERROR_AUSENCIA_COMILLAS;
                            }
                            else{
                                int i;
                                for(i=0;i<=3;i++)
                                    al->token.dato[i]='\0';
                                ce=TSintactico_PushToken(al->as,&al->token);
                                if(ce){
                                   al->es=1;   /*Error sintactico verdadero*/
                                   return ce;
                                }
                                token_reset(&al->token);
                                switch(c){
                                    case '\t': return 0;
                                    case '\n': return 0;
                                    case '\r' :return 0;
                                    case ' ':return 0;
                                    case '{':al->token.tipo=TOKEN_OBJETO_EMPIEZA;
                                             ce=TSintactico_PushToken(al->as,&al->token);
                                             if(ce){
                                                al->es=1;   /*Error sintactico verdadero*/
                                                return ce;
                                             }
                                             token_reset(&al->token);
                                             return 0;
                                    case '}':al->token.tipo=TOKEN_OBJETO_TERMINA;
                                             ce=TSintactico_PushToken(al->as,&al->token);
                                             if(ce){
                                                al->es=1;   /*Error sintactico verdadero*/
                                                return ce;
                                             }
                                             token_reset(&al->token);
                                             return 0;
                                    case '[':al->token.tipo=TOKEN_ARRAY_EMPIEZA;
                                             ce=TSintactico_PushToken(al->as,&al->token);
                                             if(ce){
                                                al->es=1;   /*Error sintactico verdadero*/
                                                return ce;
                                             }
                                             token_reset(&al->token);
                                             return 0;
                                    case ']':al->token.tipo=TOKEN_ARRAY_TERMINA;
                                             ce=TSintactico_PushToken(al->as,&al->token);
                                             if(ce){
                                                al->es=1;   /*Error sintactico verdadero*/
                                                return ce;
                                             }
                                             token_reset(&al->token);
                                             return 0;
                                    case '"':al->token.tipo=TOKEN_STRING;
                                             return 0;
                                    case ':':al->token.tipo=TOKEN_DOSPUNTOS;
                                             ce=TSintactico_PushToken(al->as,&al->token);
                                             if(ce){
                                                al->es=1;   /*Error sintactico verdadero*/
                                                return ce;
                                             }
                                             token_reset(&al->token);
                                             return 0;
                                    case ',':al->token.tipo=TOKEN_COMA;
                                             ce=TSintactico_PushToken(al->as,&al->token);
                                             if(ce){
                                                al->es=1;   /*Error sintactico verdadero*/
                                                return ce;
                                             }
                                             token_reset(&al->token);
                                             return 0;
                                }
                            }
        }
    }
    else{
        printf("ERROR LEXICO\n\n");
        al->el=ERROR_CHAR_NO_PERMITIDO;
        return ERROR_CHAR_NO_PERMITIDO;
    }
    return 0;
}


int case_token_false(TLexico* al, char c){
    int ce; /*Codigo Error*/
    if(char_valido(c)){
        int long_cad=strlen(al->token.dato);
        switch (long_cad){
            case 1: if(c=='a'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 2: if(c=='l'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 3: if(c=='s'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 4: if(c=='e'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 5: if(isalnum(c)){
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
                    else{
                        int i;
                        for(i=0;i<=4;i++)
                            al->token.dato[i]='\0';
                        ce=TSintactico_PushToken(al->as,&al->token);
                        if(ce){
                           al->es=1;   /*Error sintactico verdadero*/
                           return ce;
                        }
                        token_reset(&al->token);
                        switch(c){
                            case '\t': return 0;
                            case '\n': return 0;
                            case '\r' :return 0;
                            case ' ':return 0;
                            case '{':al->token.tipo=TOKEN_OBJETO_EMPIEZA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case '}':al->token.tipo=TOKEN_OBJETO_TERMINA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case '[':al->token.tipo=TOKEN_ARRAY_EMPIEZA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case ']':al->token.tipo=TOKEN_ARRAY_TERMINA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case '"':al->token.tipo=TOKEN_STRING;
                                     return 0;
                            case ':':al->token.tipo=TOKEN_DOSPUNTOS;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case ',':al->token.tipo=TOKEN_COMA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                        }
                    }
        }
    }
    else{
        printf("ERROR LEXICO\n\n");
        al->el=ERROR_CHAR_NO_PERMITIDO;
        return ERROR_CHAR_NO_PERMITIDO;
    }
    return 0;
}


int case_token_null(TLexico* al, char c){
    int ce; /*Codigo Error*/
    if(char_valido(c)){
        int long_cad=strlen(al->token.dato);
        switch (long_cad){
            case 1: if(c=='u'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 2: if(c=='l'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 3: if(c=='l'){
                        al->token.dato[long_cad]=c;
                        al->token.dato[long_cad+1]='\0';
                        return 0;
                    }
                    else{
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
            case 4: if(isalnum(c)){
                        printf("ERROR LEXICO\n\n");
                        al->el=ERROR_AUSENCIA_COMILLAS;
                        return ERROR_AUSENCIA_COMILLAS;
                    }
                    else{
                        int i;
                        for(i=0;i<=3;i++)
                            al->token.dato[i]='\0';
                        ce=TSintactico_PushToken(al->as,&al->token);
                        if(ce){
                           al->es=1;   /*Error sintactico verdadero*/
                           return ce;
                        }
                        token_reset(&al->token);
                        switch(c){
                            case '\t': return 0;
                            case '\n': return 0;
                            case '\r' :return 0;
                            case ' ':return 0;
                            case '{':al->token.tipo=TOKEN_OBJETO_EMPIEZA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case '}':al->token.tipo=TOKEN_OBJETO_TERMINA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case '[':al->token.tipo=TOKEN_ARRAY_EMPIEZA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case ']':al->token.tipo=TOKEN_ARRAY_TERMINA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case '"':al->token.tipo=TOKEN_STRING;
                                     return 0;
                            case ':':al->token.tipo=TOKEN_DOSPUNTOS;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                            case ',':al->token.tipo=TOKEN_COMA;
                                     ce=TSintactico_PushToken(al->as,&al->token);
                                     if(ce){
                                        al->es=1;   /*Error sintactico verdadero*/
                                        return ce;
                                     }
                                     token_reset(&al->token);
                                     return 0;
                        }
                    }
        }
    }
    else{
        printf("ERROR LEXICO\n\n");
        al->el=ERROR_CHAR_NO_PERMITIDO;
        return ERROR_CHAR_NO_PERMITIDO;
    }
    return 0;
}


int TLexico_PushChar(TLexico* al, char c){

    switch(al->token.tipo){
        case TOKEN_VACIO: return(case_token_vacio(al,c));
        case TOKEN_STRING: return(case_token_string(al,c));
        case TOKEN_NUMERO: return(case_token_numero(al,c));
        case TOKEN_TRUE: return(case_token_true(al,c));
        case TOKEN_FALSE: return(case_token_false(al,c));
        case TOKEN_NULL: return(case_token_null(al,c));
    }
    return 0;
}

